/** 1 函数封装*/
/*
最早的时候 我们是把逻辑封装在方法里

这样有个问题 如果是多人开发的话 可能会命名冲突 它们都是放在全局下的
*/
// 函数虽然拥有自己的私有作用域,里面的变量不会和外面的冲突,但是它本身的函数名还是可能会和外面冲突的
function a(){}
function b(){}


/** 2 命名空间*/
/*
减少命名冲突(没错只能是减少,命名冲突时无法彻底杜绝的)
暴露内部成员属性

但这样有个问题 如果a,b有公有变量 我们只能将它提到全局下 这样就又增加了命名冲突的可能性
*/
const zhangsan2 = {
  a() {

  }
  , b() {

  }
};

const lisi2 = {
  a() {

  }
  , b() {

  }
};


/** 3 自执行函数(闭包)*/
/*
可以保护私有变量
无法实现自动依赖
*/
const zhangsan3 = (function(){
  function a(){}
  function b(){}
  return {a}
})();
zhangsan3.a();

const lisi3 = (function(){
  function a(){}
  function b(){}
  return {a}
})();
lisi3.a()


/** 4 */
/*

*/
(function (global) {
  function add(a, b) {
    return a + b;
  }
  global.addModule = { add };
})(window);

(function (global) {
  function minus(a, b) {
    return a - b;
  }
  global.minusModule = { minus };
})(window);

(function (global, addModule, minusModule) {
  global.mathModule = { add: addModule.add, minus: minusModule.minus };
})(window, addModule/**如果不是在一个文件里,每个自执行函数是在一个单独的js文件里,那么会先通过动态创建script标签请求要加载的那个模块的自执行函数所处的js文件,然后,再执行本自执行函数*/, minusModule);

console.log(mathModule.add(2, 2));
console.log(mathModule.minus(2, 2));
